﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Brio.Framework
{
    /// <summary>
    /// Uniform Length Note Class
    /// </summary>
    [Serializable]
    public class Note
    {
        static Note()
        {
            // Populates dictionaries so that we can provide fast lookup
            // for techniques
            PopulateNoteTable(-1, -1);
            PopulateRhythmTable();
        }

        public static Dictionary<string, int> NoteTable;
        public static Dictionary<string, Tuple<int, bool>> RhythmTable;

        public Note(NoteType type, int value)
        {
            Type = type;
            Value = value;
            UniqueTechniqueID = -1;
            Marked = false;
        }

        public NoteType Type
        { get; set; }

        public int Value
        { get; set; }

        public int UniqueTechniqueID
        { get; set; }

        public bool Marked
        { get; set; }

        private static void PopulateNoteTable(int lowerBounds, int upperBounds)
        {
            // TODO: Implement lower and upper bounds
            // For now the starting note is valued 60 which is C4.
            // Population with C2 to C6
            int startingNote = 60 - Constants.OCTAVE * 2, endingNote = 60 + Constants.OCTAVE * 2;
            int startingDesignationNumber = 2;

            NoteTable = new Dictionary<string, int>();

            // What it should look like
            //for (int i = 0;  i < upperBounds - lowerBounds; i++)
            
            for (int i = 0;  i < endingNote - startingNote; i++)
            {
                // Chris and Tom :
                // http://en.wikipedia.org/wiki/C_(musical_note)
                // Look at table to understand Designation Number

                // Get the note that we are currently looking at
                int octaveNote = i % 12;
                // Get the designation number
                int designationNumber = startingDesignationNumber + (int)Math.Floor(i / Constants.OCTAVE * 1.0); 

                string noteName, noteFirstVariationName, noteSecondVariationName;

                int noteValue = startingNote + i;

                switch (octaveNote)
                {
                    case Constants.OCTAVE_C:
                        NoteTable.Add("C" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_C_SHARP:
                        NoteTable.Add("C#" + designationNumber, noteValue);
                        NoteTable.Add("Db" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_D:
                        NoteTable.Add("D" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_D_SHARP:
                        NoteTable.Add("D#" + designationNumber, noteValue);
                        NoteTable.Add("Eb" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_E:
                        NoteTable.Add("E" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_F:
                        NoteTable.Add("F" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_F_SHARP:
                        NoteTable.Add("F#" + designationNumber, noteValue);
                        NoteTable.Add("Gb" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_G:
                        NoteTable.Add("G" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_G_SHARP:
                        NoteTable.Add("G#" + designationNumber, noteValue);
                        NoteTable.Add("Ab" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_A:
                        NoteTable.Add("A" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_A_SHARP:
                        NoteTable.Add("A#" + designationNumber, noteValue);
                        NoteTable.Add("Bb" + designationNumber, noteValue);
                        break;
                    case Constants.OCTAVE_B:
                        NoteTable.Add("B" + designationNumber, noteValue);
                        break;
                }

            }

        }

        public static void PopulateRhythmTable()
        {

            RhythmTable = new Dictionary<string, Tuple<int,bool>>();

            // Move to configuration file, will allow user community to write their own syntax for notating
            
            // EXPLANATION OF IDEA:
            // Musicians are better suited at notating like : Quarter Quarter Quarter Quarter or Q Q Q Q rather than int int int int
            // but should be able to choose either way. I personally like notating with names. Musicians do not think like
            // mathematicians frankly.

            string[] wholeVariations = new string[] { "WHOLE", "Whole", "whole", "W", "w" };
            
            foreach (string wv in wholeVariations)
            {
                RhythmTable.Add(wv, new Tuple<int, bool>(Constants.RHYTHM_WHOLE_VALUE, false));
            }

            string[] wholeHoldVariations = new string[] { "WHOLE_HOLD", "Whole_Hold", "whole_hold", "WH", "Wh", "wh" };

            foreach (string whv in wholeHoldVariations)
            {
                RhythmTable.Add(whv, new Tuple<int, bool>(Constants.RHYTHM_WHOLE_VALUE, true));
            }

            string[] halfVariations = new string[] { "HALF", "Half", "half", "H", "h" };

            foreach (string hv in halfVariations)
            {
                RhythmTable.Add(hv, new Tuple<int, bool>(Constants.RHYTHM_HALF_VALUE, false));
            }

            string[] halfHoldVariations = new string[] { "HALF_HOLD", "Half_Hold", "half_hold", "HH", "Hh", "hh" };

            foreach (string hhv in halfHoldVariations)
            {
                RhythmTable.Add(hhv, new Tuple<int, bool>(Constants.RHYTHM_HALF_VALUE, true));
            }

            string[] quarterVariations = new string[] { "QUARTER", "Quarter", "quarter", "Q", "q" };

            foreach (string qv in quarterVariations)
            {
                RhythmTable.Add(qv, new Tuple<int, bool>(Constants.RHYTHM_QUARTER_VALUE, false));
            }

            string[] quarterHoldVariations = new string[] { "QUARTER_HOLD", "Quarter_Hold", "quarter_hold", "QH", "Qh", "qh" };

            foreach (string qhv in quarterHoldVariations)
            {
                RhythmTable.Add(qhv, new Tuple<int, bool>(Constants.RHYTHM_QUARTER_VALUE, true));
            }

            string[] eighthVariations = new string[] { "EIGHTH", "Eighth", "eighth", "E", "e"};

            foreach (string ev in eighthVariations)
            {
                RhythmTable.Add(ev, new Tuple<int, bool>(Constants.RHYTHM_EIGHTH_VALUE, false));
            }

            string[] eighthHoldVariations = new string[] { "EIGHTH_HOLD", "Eighth_Hold", "eighth_hold", "EH", "Eh", "eh" };

            foreach (string ehv in eighthHoldVariations)
            {
                RhythmTable.Add(ehv, new Tuple<int, bool>(Constants.RHYTHM_EIGHTH_VALUE, true));
            }

            string[] sixteenthVariations = new string[] { "SIXTEENTH", "Sixteenth", "sixteenth", "S", "s" };

            foreach (string sv in sixteenthVariations)
            {
                RhythmTable.Add(sv, new Tuple<int, bool>(Constants.RHYTHM_SIXTEENTH_VALUE, false));
            }
            
            string[] sixteenthHoldVariations = new string[] { "SIXTEENTH_HOLD", "Sixteenth_Hold", "sixteenth_hold", "SH", "Sh", "sh" };

            foreach (string shv in sixteenthHoldVariations)
            {
                RhythmTable.Add(shv, new Tuple<int, bool>(Constants.RHYTHM_SIXTEENTH_VALUE, true));
            }

            string[] thirtysecondVariations = new string[] { "THIRTYSECOND", "Thirtysecond", "thirtysecond", "T", "t" };

            foreach (string tv in thirtysecondVariations)
            {
                RhythmTable.Add(tv, new Tuple<int, bool>(Constants.RHYTHM_THIRTYSECOND_VALUE, false));
            }

            string[] thirtysecondHoldVariations = new string[] { "THIRTYSECOND_HOLD", "Thirtysecond_Hold", "thirtysecond_hold",
                                                                 "TH", "Th", "th" };

            foreach (string thv in thirtysecondHoldVariations)
            {
                RhythmTable.Add(thv, new Tuple<int, bool>(Constants.RHYTHM_THIRTYSECOND_VALUE, true));
            }

            string[] sixtyfourthVariations = new string[] { "SIXTYFOURTH", "Sixtyfourth", "sixtyfourth", "SF", "Sf", "sf" };

            foreach (string sfv in sixtyfourthVariations)
            {
                RhythmTable.Add(sfv, new Tuple<int, bool>(Constants.RHYTHM_SIXTYFOURTH_VALUE, false));
            }
            
            string[] sixtyfourthHoldVariations = new string[] { "SIXTYFOURTH_HOLD", "Sixtyfourth_Hold", "sixtyfourth_hold",
                                                                "SFH", "Sfh", "sfh" };

            foreach (string sfhv in sixtyfourthHoldVariations)
            {
                RhythmTable.Add(sfhv, new Tuple<int, bool>(Constants.RHYTHM_SIXTYFOURTH_VALUE, true));
            }
            


        }

    }

    public enum NoteType
    {
        Rest, Hold, Note
    }

}
